Skip to content

Conversation

@kmichalikk
Copy link
Collaborator

@kmichalikk kmichalikk commented Oct 14, 2025

Fixes #2933

Description

This PR fixes the bug on android that results in Screen orientation being calculated incorrectly for some time after the physical device orientation has changed. This bug seems to happen due to asynchronous nature of Screen state update emitted to react from native layer. The state contains a size that is set on the Screen frame.

The bug is more visible on slower devices, because with longer processing of consecutive commits, the delay is longer.

It can be noticed on a trivial application (some text + different background color for screen and content view) with some heavy computations artificially added to JS.

More detailed description:

In RNSScreenComponentDescriptor, on Android specifically, we call setSize() on the Screen view to hardcode its dimensions. This is needed to account for screen header size, of which React has no idea. It is however the core reason for the bug. The size which we set is outdated. Only after the asynchronous state update from native side is processed, it is corrected. This can take some time. If we comment the code for handling the header size, this problem disappears. But we cannot.

Since the code is staying here, we need to work with it. We agreed on the special value of frameSize = { 0, 0 }, for which we set YogaNode size to Undefined. This forces Yoga to recalculate the layout. It can do so because the parent view is correctly sized at this point (no calls to setSize() with outdated values). We cannot do this manually, because the descriptor doesn't have access to parent nodes. Using the commit hook, we detect the orientation change (it can compare old and new RootShadowNode, which have the correct dimensions) and set the frameSize for the ShadowNode which is passed to the descriptor afterwards.

Another problem is that the hook detects the change only once, for one instance of the shadow node. There could be more instances processed before the state is corrected. Luckily, React uses the same state instance for each shadow node instance between the updates. We take advantage of that, once reset to 0, the frameSize stays that way until some other updates changes the instance. Since we only store the screen offset and frameSize in the state, this works good enough. But it's still pretty hacky.

Changes

Description above. A new feature flag is added. When set, we register a new commit hook that checks if screen orientation changed & sets frameSize to 0. It is detected in Screen descriptor and Yoga is forced to recalculate the layout.

Before / After

before after
android-layout-bad.mov
android-layout-better.mov

Testing

Use Test2933. You can take a look at the "checkerboard" test from react-native-reanimated.

@kmichalikk kmichalikk marked this pull request as draft October 14, 2025 11:39
@kmichalikk kmichalikk force-pushed the @kmichalikk/layout-shift-on-orientation-change branch from 3209320 to 44345e5 Compare October 16, 2025 13:55
@kmichalikk kmichalikk force-pushed the @kmichalikk/layout-shift-on-orientation-change branch from 8eb4111 to 60ed155 Compare November 18, 2025 11:41
@kmichalikk kmichalikk marked this pull request as ready for review November 18, 2025 13:01
@kmichalikk kmichalikk self-assigned this Nov 19, 2025
Copy link
Member

@kkafar kkafar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job! I've left few remarks & questions. Please answer them.

@kmichalikk kmichalikk requested a review from kkafar November 20, 2025 16:50
@kkafar
Copy link
Member

kkafar commented Nov 20, 2025

@kkafar

Copy link
Member

@kkafar kkafar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few last remarks

@kmichalikk kmichalikk requested a review from kkafar November 25, 2025 11:01
Copy link
Member

@kkafar kkafar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I have two more nitpicks. After that we can land this PR.
Great job.

@kmichalikk kmichalikk requested a review from kkafar November 26, 2025 12:19
@kkafar kkafar changed the title Fix: layout shift on orientation change fix(Android): layout shift on orientation change Nov 26, 2025
Copy link
Member

@kkafar kkafar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good now. Great job!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[android] layout shift bug on new architecture

4 participants